home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 048 (1988-02-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 048 (1988-02-15)(Ossowski, Stefan)(DE)(PD).adf / Mandel / source / main.c < prev    next >
C/C++ Source or Header  |  1988-01-23  |  24KB  |  886 lines

  1. #define DEBUG
  2.  
  3. /* :ts=4
  4.  * M A N D E L B R O T  C O N S T R U C T I O N   S E T
  5.  * 
  6.  * Main Program, including some general routines
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #include <intuition/intuition.h>
  11. /* #include <graphics/display.h> */
  12. #ifdef DEBUG
  13. #    include <stdio.h>
  14. #    undef STATIC
  15. #    define STATIC    /* EMPTY */
  16. #endif
  17. #include "mandel.h"
  18.  
  19. struct IntuitionBase *IntuitionBase;
  20. struct GfxBase *GfxBase;
  21. struct LayersBase *LayersBase;
  22.  
  23. struct TextAttr Topaz80 = {
  24.     (STRPTR) "topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT    };
  25.  
  26. struct TextAttr Topaz60 = {
  27.     (STRPTR) "topaz.font", TOPAZ_SIXTY, FS_NORMAL, FPF_ROMFONT    };
  28.  
  29. struct NewScreen MandelNScreen =
  30. {
  31.     0, 0, 320, 256,         /* LeftEdge, TopEdge, Width, Height */
  32.     4,                      /* Depth */
  33.     2, 1,                   /* DetailPen, BlockPen */
  34.     NULL,                   /* viewmode LORES */
  35.     CUSTOMSCREEN,           /* type */
  36.     &Topaz80,               /* Font (default) */
  37.     (UBYTE *)"Mandelbrot Construction Set V1.0" /* DefaultTitle for menubar */
  38. };
  39.  
  40. struct NewWindow MainNWindow =
  41. {
  42.     0, 0, 0, 0,            /* LeftEdge, TopEdge, Width, Height */
  43.     2, 1,                  /* DetailPen, BlockPen */
  44.     CLOSEWINDOW | MENUPICK | MOUSEBUTTONS | SIZEVERIFY |
  45.         MENUVERIFY,
  46.     WINDOWCLOSE | ACTIVATE | WINDOWSIZING | WINDOWDRAG |
  47.          WINDOWDEPTH | NOCAREREFRESH | SMART_REFRESH | GIMMEZEROZERO,
  48.     NULL,                    /* FirstGadget */
  49.     NULL,                   /* default CheckMark */
  50.     (UBYTE *) "Mandelbrot Construction Window",     /* Title */
  51.     NULL,                   /* Screen */
  52.     NULL,                   /* BitMap */
  53.     60, 25,                 /* MinWidth, MinHeight */
  54.     -1, -1,                 /* MaxWidth, MaxHeight */
  55.     CUSTOMSCREEN            /* Screen type */
  56. };
  57.  
  58. struct BorderInfo borderinfo;
  59.  
  60. struct IntuiText PositiveText =
  61.     {    AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  62.         AUTOLEFTEDGE, AUTOTOPEDGE, NULL, (UBYTE *) "Continue", NULL    },
  63. NegativeText =
  64.     {    AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  65.         AUTOLEFTEDGE, AUTOTOPEDGE, &Topaz60, (UBYTE *) "Cancel", NULL    };
  66.  
  67. STATIC SHORT XY1[] = { 0,0, 0,13, 78,13, 78,0, 0,0 };
  68. STATIC SHORT XY2[] = { 0,0, 0,17, 82,17, 82,0, 0,0 };
  69. STATIC struct Border border[] = {
  70.     {     0,  0, 2,0, JAM1, 5, XY1, &border[1] },
  71.     {    -2, -2, 3,0, JAM1, 5, XY2, NULL }
  72. };
  73. struct Gadget NegativeGadget = {
  74.     NULL, -100, -20, 79, 14,    /* next, LTWH */
  75.     GADGHCOMP | GRELBOTTOM | GRELRIGHT,
  76.     RELVERIFY | ENDGADGET,
  77.     BOOLGADGET | REQGADGET,
  78.     (APTR) &border[0], NULL,
  79.     &NegativeText, 0, NULL,
  80.     NEGGADGETID, NULL    };
  81. struct Gadget PositiveGadget = {
  82.     &NegativeGadget, 20, -20, 79, 14,    /* next, LTWH */
  83.     GADGHCOMP | GRELBOTTOM,
  84.     RELVERIFY | ENDGADGET,
  85.     BOOLGADGET | REQGADGET,
  86.     (APTR) &border[0], NULL,
  87.     &PositiveText, 0, NULL,
  88.     POSGADGETID, NULL    };
  89.  
  90. USHORT ColorMap[MAXDEPTH];
  91. bool ColorMapValid = FALSE;
  92. UBYTE PenTable[MAXDEPTH];
  93. unsigned PenTableMode = MODULO;
  94. short RangeWidth = 2;
  95.  
  96. struct Screen *MandelScreen = NULL;  /* Pointer for OpenScreen return value */
  97. struct Window *MainWindow = NULL;    /* Idem for OpenWindow */
  98.  
  99.  
  100. void (*WritePixelDepth)() = ZQuadMinC;
  101.  
  102. double    LeftEdge = -0.800,    /* Left edge of the picture */
  103.     RightEdge = 2.100,
  104.     TopEdge = 1.200,
  105.     BottomEdge = -1.200;
  106.  
  107. double    CXStep,               /* Stepsize through the complex plane */
  108.     CYStep;
  109. int    PixelStep=1,              /* Stepsize on the screen*/
  110.     MaxDepth=100;             /* Maximum iteration count */
  111.     NumColors;                  /* Number of colors on the screen */
  112.  
  113. unsigned short FrameX1, FrameX2,
  114.     FrameY1, FrameY2;
  115.  
  116. short MouseStatus = NOTFRAMING;/* Where we are in the process of */
  117.                               /* selecting a frame */
  118.  
  119. bool finished = FALSE;          /* TRUE to stop the program */
  120. bool Saved = TRUE;              /* Indicates the picture has been SAVEd */
  121. bool NameValid = FALSE;          /* Indicates the file name is valid */
  122. bool StillDrawing = FALSE;      /* Are we still drawing ? */
  123.  
  124. /* Manx startup stubs, to save some memory. Not useful with Lattice! */
  125.  
  126. #ifdef MANX_C
  127. _cli_parse() {}
  128. _wb_parse() {}
  129. #endif
  130.  
  131. /* M A I N   E N T R Y   P O I N T */
  132.  
  133. main()
  134. {
  135.     register ULONG Class;                    /* IntuiMessage class */
  136.     register USHORT Code;                    /*  and Code field */
  137.     struct IntuiMessage *message;            /* Expected message pointer */
  138.  
  139. /* Open each of the libraries and check for a NULL return, which
  140.  * indicates unavailability.
  141.  */
  142.  
  143.     IntuitionBase = (struct IntuitionBase *)
  144.         OpenLibrary ("intuition.library", LIBRARY_VERSION);
  145.     if (IntuitionBase == NULL) MyExit ("Can't open Intuition V1.2 or newer!");
  146.  
  147.     GfxBase = (struct GfxBase *)
  148.         OpenLibrary("graphics.library", LIBRARY_VERSION);
  149.     if (GfxBase == NULL) MyExit ("Can't open Gfx V1.2 or newer!");
  150.  
  151.     LayersBase = (struct LayersBase *)
  152.         OpenLibrary("layers.library", LIBRARY_VERSION);
  153.     if (LayersBase == NULL) MyExit ("Can't open Layers V1.2 or newer!");
  154.  
  155.     if (InitDisplay((bool)FALSE)) MyExit ("Can't initialise the display properly!");
  156.  
  157.     CalcCSteps();
  158.  
  159. again:
  160.     finished = FALSE;
  161.     while (!finished) {
  162.         /* Wait for message port to become not empty, and extract the msg */
  163.         WaitPort(MainWindow->UserPort);
  164.         while ( message = (struct IntuiMessage *)
  165.             GetMsg(MainWindow->UserPort) ) {
  166. gotmessage:
  167.             Class  = message->Class;
  168.             Code   = message->Code;
  169.  
  170.             if (Class & ~(MOUSEBUTTONS | INTUITICKS)) {
  171.                 ReplyMsg(message);        /* Pointer is not valid anymore */
  172.             }
  173.  
  174.             switch (Class) {
  175.             case MENUPICK:
  176.                 GotMenu(Code); break;
  177.             case MOUSEBUTTONS:
  178.             case INTUITICKS:
  179.                 CheckMouse(Class, Code, message->MouseX, message->MouseY,
  180.                     message->Seconds, message->Micros);
  181.                 ReplyMsg(message);
  182.                 break;
  183.             case SIZEVERIFY:
  184.                 StopFraming();                 /* Fall Through to MenuVerify */
  185.             case MENUVERIFY:
  186.                 break;        /* Just make sure there is no half-drawn frame */
  187.             case CLOSEWINDOW:
  188.                 finished = TRUE;
  189.                 break;
  190.             /* default: Ignore strange messages */
  191.             }  /* End Switch The Class Of The Message */
  192.         }  /* End While There Is A Message */
  193.     }  /* End While Not Finished */
  194.  
  195.     /* So we are finished. 
  196.      * And, by the way, are we SURE we are finished alltogether ??
  197.      */
  198.     if (!Sure()) {
  199.         backto again;
  200.     }
  201.  
  202.     CleanupDisplay((bool)TRUE);
  203.     MyExit(NULL);                       /* Indicate Good Exit */
  204. }  /* End of main */
  205.  
  206.  
  207. /* Initialize the screen and the windows and the menus */
  208.  
  209. bool InitDisplay(borderless)
  210. bool borderless;
  211. {
  212.     USHORT ViewModes = MandelNScreen.ViewModes;
  213.     struct Screen WBScreen;
  214.     int i;
  215.     StopFraming();
  216.  
  217.     Saved = TRUE;    /* We can easily reconstruct this `picture' */
  218.  
  219.     /* Get Left, Top, Width, Height */
  220.     GetScreenData(&WBScreen, (long)sizeof(WBScreen),
  221.         (long)WBENCHSCREEN, NULL);
  222.     MandelNScreen.Width = WBScreen.Width;
  223.     MandelNScreen.Height = WBScreen.Height;
  224.     /* Maybe we have an interlaced WorkBench screen */
  225.     if (WBScreen.ViewPort.Modes & LACE) MandelNScreen.Height >>= 1;
  226.     /* And maybe, if we use MWB, it isn't hires... */
  227.     if (!(WBScreen.ViewPort.Modes & HIRES)) MandelNScreen.Width <<= 1;
  228.  
  229.     if (ViewModes & LACE) MandelNScreen.Height <<= 1;
  230.  
  231.     if (ViewModes & HIRES) {
  232.         MandelNScreen.Depth = 4;
  233.         NumColors = 16;
  234.  
  235.         /* Avoid a bug in MrgCop()?? if you have a PAL machine with */
  236.         /* a screen wider than 640 taller than 213 and with 4 bitplanes */
  237.  
  238.         if (MandelNScreen.Width > 640)
  239.             MandelNScreen.Width = 640;
  240.     } else {
  241.         MandelNScreen.Depth = 5;
  242.         NumColors = 32;
  243.         MandelNScreen.Width >>= 1;
  244.     }
  245.  
  246.     if ( !MandelScreen && !(MandelScreen = OpenScreen(&MandelNScreen)) ) {
  247.         skipto abort;
  248.     }
  249.  
  250.     if (ColorMapValid)
  251.         LoadRGB4(&MandelScreen->ViewPort, ColorMap, (long) NumColors);
  252.  
  253.     MainNWindow.Screen = MandelScreen;
  254.  
  255.     if (MainNWindow.Height < MainNWindow.MinHeight) {
  256.         /* First time we open the window */
  257.         MainNWindow.LeftEdge = 0;
  258.         MainNWindow.TopEdge  = MandelScreen->BarHeight;
  259.         MainNWindow.Width    = MandelScreen->Width;
  260.         MainNWindow.Height   = MandelScreen->Height - MainNWindow.TopEdge;
  261.     } else {
  262.         if (ViewModes & HIRES) {
  263.             MainNWindow.LeftEdge <<= 1;
  264.             MainNWindow.Width <<= 1;
  265.         }
  266.         if (ViewModes & LACE) {
  267.             MainNWindow.TopEdge <<= 1;
  268.             MainNWindow.Height <<= 1;
  269.         }
  270.     }
  271.  
  272.     /* Check for windows that can't be opened */
  273.  
  274.     if (MainNWindow.LeftEdge + MainNWindow.Width > MandelScreen->Width)
  275.         MainNWindow.Width = MandelScreen->Width - MainNWindow.LeftEdge;
  276.  
  277.     if (MainNWindow.TopEdge + MainNWindow.Height > MandelScreen->Height)
  278.         MainNWindow.Height = MandelScreen->Height - MainNWindow.TopEdge;
  279.  
  280.     if ( !MainWindow && !(MainWindow = OpenWindow(&MainNWindow)) ) {
  281.         skipto abort;
  282.     }
  283.  
  284.     SetMenuStrip(MainWindow, MandelMenu);
  285.     if (borderless) {
  286.         DoBorderless(MainWindow, &borderinfo);
  287.     }
  288.  
  289.     InitPenTable();
  290.  
  291.     return FALSE;
  292.  
  293. abort:
  294.     CleanupDisplay((bool) TRUE);
  295.     return TRUE;
  296.  
  297. }
  298.  
  299. bool CleanupDisplay(everything)
  300. bool everything;
  301. {
  302.     bool wasborderless;
  303.     int i;
  304.  
  305.     StopDrawing();
  306.     StopFraming();
  307.  
  308.     wasborderless = (MainWindow != NULL) &&
  309.         ((MainWindow->Flags & BORDERLESS) != 0);
  310.  
  311.     if (MainWindow) {
  312.         /* Save window appearance for later, in low-res non-lace pixels */
  313.         MainNWindow.LeftEdge = MainWindow->LeftEdge;
  314.         MainNWindow.TopEdge  = MainWindow->TopEdge;
  315.         MainNWindow.Width    = MainWindow->Width;
  316.         MainNWindow.Height   = MainWindow->Height;
  317.  
  318.         ClearMenuStrip(MainWindow);        /* Remove menu strip */
  319.         CloseWindow(MainWindow);        /* Finally close it */
  320.         MainWindow = NULL;
  321.     }
  322.  
  323.     /* Save the colors we may have established with great care */
  324.  
  325.     if (MandelScreen) {
  326.         for (i=0; i < NumColors; i++) {
  327.             ColorMap[i] = GetRGB4(MandelScreen->ViewPort.ColorMap, i);
  328.         }
  329.         ColorMapValid = TRUE;
  330.  
  331.         if (MandelScreen->ViewPort.Modes & HIRES) {
  332.             MainNWindow.LeftEdge >>= 1;
  333.             MainNWindow.Width >>= 1;
  334.         }
  335.         if (MandelScreen->ViewPort.Modes & LACE) {
  336.             MainNWindow.TopEdge >>= 1;
  337.             MainNWindow.Height >>= 1;
  338.         }
  339.  
  340.         /* Close the screen only if `everything' must be cleaned up */
  341.  
  342.         if (everything) {
  343.             CloseScreen(MandelScreen);
  344.             MandelScreen = NULL;
  345.         }
  346.     }
  347.  
  348.     return wasborderless;
  349. }
  350.  
  351. bool DoBorderless(window, borderinfo)
  352. struct Window *window;
  353. struct BorderInfo *borderinfo;
  354. {
  355.     /* Make window borderless */
  356.  
  357. /* register struct Layer_Info *LayerInfo = &window->WScreen->LayerInfo; */
  358. #define LayerInfo    NULL            /* Since V1.2 */
  359.     register struct Layer *Layer = window->RPort->Layer;
  360.     register long movex;
  361.     register long movey;
  362.     register long sizex;
  363.     register long sizey;
  364.     bool Success = FALSE;
  365.  
  366.     if (window->Flags & BORDERLESS)    return TRUE;
  367.  
  368.     LockLayer(LayerInfo, Layer);
  369.  
  370.     window->Flags |= BORDERLESS;
  371.  
  372.     movex = -window->BorderLeft;
  373.     movey = -window->BorderTop;
  374.     sizex = window->BorderRight - movex;
  375.     sizey = window->BorderBottom - movey;
  376.  
  377.     window->BorderLeft =
  378.     window->BorderTop =
  379.     window->BorderRight =
  380.     window->BorderBottom = 0;
  381.  
  382.     window->GZZWidth += sizex;
  383.     window->GZZHeight += sizey;
  384.  
  385.     if ( MoveLayer(LayerInfo, Layer, movex, movey) ) {
  386.         Success = SizeLayer(LayerInfo, Layer, sizex, sizey);
  387.         if (!Success) {
  388.               sizex = sizey = 0;
  389.         }
  390.     } else {
  391.         movex = movey = sizex = sizey = 0;
  392.     }
  393.     UnlockLayer(Layer);
  394.  
  395.     borderinfo->MoveX = movex;
  396.     borderinfo->MoveY = movey;
  397.     borderinfo->SizeX = sizex;
  398.     borderinfo->SizeY = sizey;
  399.  
  400.     /* Done making borderless */
  401.  
  402.     if (Success) {
  403.         return Success;
  404.     } else {    /* Try to clean up the mess */
  405.         UndoBorderless(window, borderinfo);
  406.         return FALSE;
  407.     }
  408. #undef LayerInfo
  409. }
  410.  
  411. void UndoBorderless(window, borderinfo)
  412. struct Window *window;
  413. struct BorderInfo *borderinfo;
  414. {
  415.     /* ``Another fine mess you got me into!'' (Oliver Hardy) */
  416.  
  417. /*    register struct Layer_Info *LayerInfo = &window->WScreen->LayerInfo; */
  418. #define LayerInfo    NULL            /* Since V1.2 */
  419.     register struct Layer *Layer = window->RPort->Layer;
  420.     register long movex = borderinfo->MoveX;
  421.     register long movey = borderinfo->MoveY;
  422.     register long sizex = borderinfo->SizeX;
  423.     register long sizey = borderinfo->SizeY;
  424.     bool Success = FALSE;
  425.  
  426.     if (!(window->Flags & BORDERLESS))    return;
  427.  
  428.     LockLayer(LayerInfo, Layer);
  429.     SizeLayer(LayerInfo, Layer, -sizex, -sizey);
  430.     MoveLayer(LayerInfo, Layer, -movex, -movey);
  431.  
  432.     window->GZZWidth -= sizex;
  433.     window->GZZHeight -= sizey;
  434.  
  435.     window->BorderLeft = -movex;
  436.     window->BorderTop = -movey;
  437.     window->BorderRight = sizex + movex;
  438.     window->BorderBottom = sizey + movey;
  439.  
  440.     window->Flags &= ~BORDERLESS;
  441.  
  442.     RefreshWindowFrame(window);
  443.  
  444.     UnlockLayer(Layer);
  445.  
  446.     /* Done Undoing Borderless */
  447. #undef LayerInfo
  448. }
  449.  
  450. void MyExit(status)
  451. char *status;
  452. {
  453. #ifndef DEBUG2
  454.     static char message[] = "\
  455. \0\144\25Mandelbrot Construction Set -- By KosmoSoft Productions\0a\
  456. \0\144\41                                                                 \0";
  457. /*      3^5^  10^    ^  20^    ^  30^    ^  40^    ^  50^  55^58^     */
  458.     register char *c=message+65;
  459.  
  460.     if (status) {
  461.         /* Center the message. Notice `60' is even. */
  462.         /* We assume WORD alignment for the string. */
  463.  
  464.         *((WORD *) (message+60)) = 320 - (strlen(status) << 2);
  465.         while ((*(c++) = *(status++)) && c < message + 127);
  466.         *c = 0;
  467.  
  468.         /* Let's be paranoid for a change... */
  469.         if (!IntuitionBase) IntuitionBase = (struct IntuitionBase *)
  470.             OpenLibrary ("intuition.library", 0L);
  471.         if (IntuitionBase)
  472.             DisplayAlert(RECOVERY_ALERT, message, 50L);
  473.         else {    /* AT_Recovery | AG_OpenLib | AO_Intuition */
  474.             CPTR AlertParameter = (CPTR) FindTask(NULL);
  475.             Alert(0x00038004L, &AlertParameter);
  476.         }
  477.  
  478.         status=1;
  479.     }
  480. #else
  481.     if (status) {
  482.         fprintf(stderr, "Mandelbrot Construction Set Error:\n    %s\n",
  483.             status);
  484.         status = 1;
  485.     }
  486. #endif
  487.     CleanupDisplay((bool) TRUE);
  488.     if (IntuitionBase) CloseLibrary(IntuitionBase);
  489.     if (LayersBase) CloseLibrary(LayersBase);
  490.     if (GfxBase) CloseLibrary(GfxBase);
  491.     exit ((int) (status != NULL));
  492. }
  493.  
  494. bool Sure()
  495. {
  496.     bool Result;
  497.     ULONG OldIDCMP = MainWindow->IDCMPFlags;
  498.  
  499.     static struct IntuiText Body[] =
  500.     {
  501.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  502.             25, 10, NULL, (UBYTE *) "You are going to", &Body[1]    },
  503.         {    MYFRONTPEN+1, AUTOBACKPEN, AUTODRAWMODE,
  504.             57, 25, &Topaz60, (UBYTE *) "destroy", &Body[2]    },
  505.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  506.             33, 40, NULL, (UBYTE *) "your picture !", NULL    }
  507.     };
  508.  
  509.     if (Saved) return TRUE;
  510.  
  511.     ModifyIDCMP(MainWindow, OldIDCMP &~ (MENUVERIFY | SIZEVERIFY | REQVERIFY));
  512.     Result = AutoRequest(MainWindow, &Body[0], &PositiveText, &NegativeText,
  513.         NULL, NULL, 200L, 90L);
  514.     ModifyIDCMP(MainWindow, OldIDCMP);
  515.  
  516.     return Result;
  517. }
  518.  
  519. /***********************************************************************
  520.  * Render a requester in a window. If it won't fit, open a new window.
  521.  * This new window will share the IDCMP port with the original
  522.  * window. This is to save memory, signal bits and VERIFY deadlocks.
  523.  * Returns the window in which the requester actually appears.
  524.  */
  525.  
  526. struct Window *MyRequest(request, window)
  527. struct Requester *request;
  528. struct Window *window;
  529. {
  530.     static struct NewWindow newwindow = {
  531.         0, 0, 0, 0, 2, 1,
  532.         NULL,            /* IDCMP flags -- port shared with main window */
  533.         WINDOWDEPTH | WINDOWDRAG | ACTIVATE | SIMPLE_REFRESH | NOCAREREFRESH,
  534.         NULL, NULL, NULL, NULL,
  535.         NULL, 0, 0, 0, 0, NULL    };
  536.     int width, height, left, top;
  537.     int borderleft, borderright, bordertop, borderbottom;
  538.     struct Window *oldwindow = window;
  539.  
  540.     borderleft   = window->WScreen->WBorLeft;
  541.     borderright  = window->WScreen->WBorRight;
  542.     bordertop    = window->WScreen->BarHeight + 1;
  543.     borderbottom = window->WScreen->WBorBottom;
  544.  
  545.     /* Center the requester in the given window.
  546.      * If impossible, open a new window to the place the requester in.
  547.      */
  548.  
  549.      width = window->Width - borderleft - borderright;
  550.      height = window->Height - bordertop - borderbottom;
  551.      left = ((width - request->Width) >> 1) + borderleft;
  552.      top = ((height - request->Height) >> 1) + bordertop;
  553.  
  554.      if (width < request->Width || height < request-> Height) {
  555.          /* Window too small. Open a new one */
  556.         newwindow.Width = request->Width + 2 * borderleft;
  557.         newwindow.Height = request->Height + bordertop + borderbottom;
  558.         newwindow.LeftEdge = newwindow.TopEdge = 0;
  559.         newwindow.Title = window->Title;
  560.         newwindow.Screen = window->WScreen;
  561.         newwindow.Type = window->WScreen->Flags & SCREENTYPE;
  562.  
  563.         if (window = OpenWindow(&newwindow)) {
  564.             window->UserPort = oldwindow->UserPort;
  565.             /* Upen up the other port */
  566.             ModifyIDCMP(window, GADGETUP);
  567.         }
  568.  
  569.         request->LeftEdge = borderleft;
  570.         request->TopEdge = bordertop;
  571.     } else {    /* The requester fits. Center it! */
  572.         request->LeftEdge = left;
  573.         request->TopEdge = top;
  574.     }
  575.  
  576.     if (window && Request(request, window)) return window;
  577.  
  578.     if (window) CloseWindowSafely(window);
  579.     return NULL;
  580. }
  581.  
  582. void EndMyRequest(request, window, original)
  583. struct Requester *request;
  584. struct Window *window, *original;
  585. {
  586.     EndRequest(request, window);
  587.     if (window != original) CloseWindowSafely(window);
  588. }
  589.  
  590. /*************************************************************************
  591.  * Wait on a request posted by MyRequest.
  592.  * Returns when a gadget with GadgetID >= POSGADGETID is released,
  593.  * so Gadgets with an ID < POSGADGETID will be ignored.
  594.  * Any messages other than GADGETUP will be ignored.
  595.  */
  596.  
  597. int WaitMyRequest(window)
  598. struct Window *window;
  599. {
  600.     int ID = 0;
  601.     struct IntuiMessage *message;
  602.     struct Gadget *Gadget;
  603.     ULONG Class;
  604.     ULONG OldIDCMP = window->IDCMPFlags;
  605.  
  606.     if (!window)
  607.         return NEGGADGETID;
  608.  
  609.     ModifyIDCMP(window, GADGETUP);
  610.     while (ID < POSGADGETID) {
  611.         WaitPort(window->UserPort);
  612.         while (message = (struct IntuiMessage *) GetMsg(window->UserPort) ) {
  613.             Class = message->Class;
  614.             Gadget = (struct Gadget *)message->IAddress;
  615.             ReplyMsg(message);
  616.             if (Class != GADGETUP) continue;
  617.             ID = Gadget->GadgetID;
  618.             if (ID >= POSGADGETID) break; /* Also gets out of outer loop */
  619.         }
  620.     }
  621.     ModifyIDCMP(window, OldIDCMP);
  622.     return ID;
  623. }
  624.  
  625. void RectDraw(rp, x1, y1, x2, y2)
  626. struct RastPort *rp;
  627. SHORT x1, y1, x2,y2;
  628. {
  629.     Move(rp, (long) x1, (long) y1);
  630.     Draw(rp, (long) x2, (long) y1);
  631.     Draw(rp, (long) x2, (long) y2);
  632.     Draw(rp, (long) x1, (long) y2);
  633.     if (y2 > y1) y1++; else y1--;    /* Don't XOR the first pixel twice */
  634.     Draw(rp, (long) x1, (long) y1);
  635. }
  636.  
  637. void CrossDraw(rp, x, y, left, right, top, bottom)
  638. struct RastPort *rp;
  639. SHORT x, y, top, bottom, left, right;
  640. {
  641.     Move(rp, (long) left, (long) y);
  642.     Draw(rp, (long) right, (long) y);
  643.     Move(rp, (long) x, (long) top);
  644.     Draw(rp, (long) x, (long) bottom);
  645. }
  646.  
  647. void DisableSystemGadgets(gadget)
  648. struct Gadget *gadget;
  649. {
  650.     while (gadget) {
  651.         if (gadget->GadgetType & SYSGADGET) {
  652.             /* Ghost everything except the Title/Dragbar */
  653.             if ((gadget->GadgetType & 0x00F0) != WDRAGGING)
  654.                 OffGadget(gadget, MainWindow, NULL);
  655.             gadget->Flags |= GADGDISABLED;
  656.         }
  657.         gadget = gadget->NextGadget;
  658.     }
  659. }
  660.  
  661. void EnableSystemGadgets(gadget)
  662. struct Gadget *gadget;
  663. {
  664.     USHORT Flags = 0;
  665.  
  666.     while (gadget) {
  667.         if (gadget->GadgetType & SYSGADGET) {
  668.             Flags |= gadget->Flags;
  669.             gadget->Flags &= ~GADGDISABLED;
  670.         }
  671.         gadget = gadget->NextGadget;
  672.     }
  673.     /* Unghost everthing if necessary */
  674.     if (Flags & GADGDISABLED)    RefreshWindowFrame(MainWindow);
  675. }
  676.  
  677. void StopFraming()
  678. {
  679.     if (MainWindow) {
  680.         EnableSystemGadgets(MainWindow->FirstGadget);
  681.         ModifyIDCMP(MainWindow, MainWindow->IDCMPFlags & ~INTUITICKS);
  682.     }
  683.     MouseStatus = NOTFRAMING;
  684. }
  685.  
  686. void CheckMouse(Class, Code, MouseX, MouseY, Secs, Micros)
  687. ULONG Class;
  688. USHORT Code;
  689. SHORT MouseX, MouseY;
  690. ULONG Secs, Micros;
  691. {
  692.     register SHORT top = MainWindow->BorderTop,
  693.         bottom = MainWindow->Height - MainWindow->BorderBottom - 1,
  694.         left = MainWindow->BorderLeft,
  695.         right = MainWindow->Width - MainWindow->BorderRight - 1;
  696.     static ULONG OldSecs, OldMicros;
  697.     static SHORT MidX, MidY;
  698.  
  699.     if (StillDrawing || MouseStatus != FLASHING &&
  700.         (MouseX < left || MouseX > right || MouseY < top || MouseY > bottom))
  701.         return;
  702.  
  703.     MouseX -= left;
  704.     MouseY -= top;
  705.  
  706.     if (Class == MOUSEBUTTONS) {
  707.         if (Code == SELECTDOWN) {
  708.             /* We selected a point */
  709.             switch (MouseStatus) {
  710.             case NOTFRAMING:
  711.             case FLASHING:
  712.                 MouseStatus = NOPOINT;
  713.                 DisableSystemGadgets(MainWindow->FirstGadget);
  714.                 ModifyIDCMP(MainWindow, MainWindow->IDCMPFlags | INTUITICKS);
  715.                 /* Now we can select our first corner */
  716.                 break;
  717.             case NOPOINT:
  718.                 FrameX1 = FrameX2 = MouseX;
  719.                 FrameY1 = FrameY2 = MouseY;
  720.                 MouseStatus = POINT1;
  721.                 OldMicros = Micros;
  722.                 OldSecs = Secs;
  723.                 /* We have the first point. Now go for the second */
  724.                 break;
  725.             case POINT1:
  726.                 if (DoubleClick(OldSecs, OldMicros, Secs, Micros)) {
  727.                     /* Did we double-click? Then we have selected a center */
  728.                     MouseStatus = CENTERFRAMING;
  729.                     MidX = FrameX1;
  730.                     MidY = FrameY1;
  731.                     break;
  732.                 }
  733.                 FrameX2 = MouseX;
  734.                 FrameY2 = MouseY;
  735.                 /* Fall through to CENTERFRAMING */
  736.             case CENTERFRAMING:
  737.                 if (FrameX1 == FrameX2 || FrameY1 == FrameY2) break;
  738.                 EnableSystemGadgets(MainWindow->FirstGadget);
  739.                 MouseStatus = FLASHING;
  740.                 /* Point 1 should be upper left */
  741.                 if (FrameX2 < FrameX1) {
  742.                     /* I DO know I am reusing a variable here. Sorry! */
  743.                     left=FrameX2; FrameX2=FrameX1; FrameX1=left;
  744.                 }
  745.                 if (FrameY2 < FrameY1) {
  746.                     left=FrameY2; FrameY2=FrameY1; FrameY1=left;
  747.                 }
  748.                 break;
  749.             }    /* End switch MouseStatus */
  750.         }    /* End if Code == SELECTDOWN */
  751.         return;
  752.     }    /* End if Class == MOUSEBUTTONS */
  753.  
  754.     /* We are moving the mouse. Show something! */
  755.  
  756.     SetDrMd(MainWindow->RPort, (ULONG) COMPLEMENT);
  757.  
  758.     switch (MouseStatus) {
  759.     /* case NOTFRAMING: */
  760.     /*    return; */
  761.     case NOPOINT:
  762.         FrameX1 = FrameX2 = MouseX;
  763.         FrameY1 = FrameY2 = MouseY;
  764.         /* WaitBOVP(&MandelScreen->ViewPort); */
  765.         WaitTOF();
  766.         CrossDraw(MainWindow->RPort, FrameX1, FrameY1,
  767.                     0, MainWindow->GZZWidth-1, 0, MainWindow->GZZHeight-1);
  768.         /* WaitBOVP(&MandelScreen->ViewPort);    */
  769.         WaitTOF();
  770.         CrossDraw(MainWindow->RPort, FrameX1, FrameY1,
  771.                     0, MainWindow->GZZWidth-1, 0, MainWindow->GZZHeight-1);
  772.         break;
  773.     case CENTERFRAMING:
  774.         FrameX1 = MouseX;
  775.         FrameY1 = MouseY;
  776.         FrameX2 = 2*MidX - FrameX1;
  777.         FrameY2 = 2*MidY - FrameY1;
  778.         skipto flashing;
  779.     case POINT1:
  780.         FrameX2 = MouseX;
  781.         FrameY2 = MouseY;
  782.         /* Deliberate Fall-Through to FLASHING */
  783.     case FLASHING:
  784. flashing:
  785.         /* WaitBOVP(&MandelScreen->ViewPort);    */
  786.         WaitTOF();
  787.         RectDraw(MainWindow->RPort, FrameX1, FrameY1, FrameX2, FrameY2);
  788.         /* WaitBOVP(&MandelScreen->ViewPort);    */
  789.         WaitTOF();
  790.         RectDraw(MainWindow->RPort, FrameX1, FrameY1, FrameX2, FrameY2);
  791.     }
  792. }
  793.  
  794. void InitPenTable()
  795. {
  796.     register int i;
  797.  
  798.     switch (PenTableMode) {
  799.     case MODULO:
  800.         PenTable[0] = 0;
  801.         for (i=1; i<MAXDEPTH; i++) PenTable[i] = 1 + i % (NumColors - 1);
  802.         break;
  803.     case RANGES:
  804.         PenTable[0] = 0;
  805.         for (i=1; i<MAXDEPTH; i++)
  806.             PenTable[i] = 1 + (i/RangeWidth) % (NumColors - 1);
  807.     case SELECT:
  808.         /* Don't change the table if it is user-defined */
  809.         break;
  810.     }
  811. }
  812.  
  813. void SelectMenu(MenuNum, CheckIt)
  814. LONG MenuNum;
  815. bool CheckIt;
  816. {
  817.     struct MenuItem *Item = ItemAddress(MandelMenu, MenuNum);
  818.  
  819.     ClearMenuStrip(MainWindow);
  820.  
  821.     if (CheckIt)
  822.         Item->Flags |= CHECKED;
  823.     else
  824.         Item->Flags &= ~CHECKED;
  825.  
  826.     SetMenuStrip(MainWindow, MandelMenu);
  827. }
  828.  
  829. void MakeMAND(mand)
  830. struct Mand *mand;
  831. {
  832.     int i;
  833.  
  834.     mand->MandID = MAND;
  835.     mand->Size = sizeof(struct Mand);
  836.     mand->MaxDepth = MaxDepth;
  837.     mand->RangeWidth = RangeWidth;
  838.  
  839.     mand->RainDist = RainbowDistance;
  840.     mand->RainRMax = RainbowRMax;
  841.     mand->RainGMax = RainbowGMax;
  842.     mand->RainBMax = RainbowBMax;
  843.  
  844.     for (i=0; i < sizeof(mand->Coords); i++)
  845.         mand->Coords[i] = '\0';
  846.     sprintf(&mand->Coords[0], "%1.10g %1.10g %1.10g %1.10g",
  847.         LeftEdge, RightEdge, TopEdge, BottomEdge);
  848. }
  849.  
  850. bool InterpretMAND(mand)
  851. struct Mand *mand;
  852. {
  853.     double NewLeftEdge, NewRightEdge, NewTopEdge, NewBottomEdge;
  854.  
  855.     /* Perform some checks on correctness of the chunk */
  856.     if (mand->MandID != MAND || mand->Size > sizeof(struct Mand) ||
  857.         mand->MaxDepth > MAXDEPTH || mand->RangeWidth > MAXDEPTH)
  858.         return FALSE;
  859.  
  860.     if (sscanf(&mand->Coords[0], "%lf %lf %lf %lf",
  861.         &NewLeftEdge, &NewRightEdge, &NewTopEdge, &NewBottomEdge) < 4)
  862.         return FALSE;
  863.  
  864.     MaxDepth    = mand->MaxDepth;
  865.     RangeWidth  = mand->RangeWidth;
  866.  
  867.     LeftEdge    = NewLeftEdge;
  868.     RightEdge   = NewRightEdge;
  869.     TopEdge     = NewTopEdge;
  870.     BottomEdge  = NewBottomEdge;
  871.     CalcCSteps();
  872.  
  873.     RainbowDistance = mand->RainDist;
  874.     RainbowRMax = mand->RainRMax;
  875.     RainbowGMax = mand->RainGMax;
  876.     RainbowBMax = mand->RainBMax;
  877.  
  878.     return TRUE;
  879. }
  880.  
  881. void CalcCSteps()
  882. {
  883.     CXStep = (double) (RightEdge - LeftEdge) / ( MainWindow->GZZWidth - 1);
  884.     CYStep = (double) (TopEdge - BottomEdge) / ( MainWindow->GZZHeight - 1);
  885. }
  886.